import './index.css'
import * as THREE from 'three'
import {
    OrbitControls
} from 'three/examples/jsm/controls/OrbitControls'


/**
 * Size
 */
const Size = {
    width: window.innerWidth,
    height: window.innerHeight
}


/**
 * Scene
 */
const scene = new THREE.Scene()

/**
 * Camera
 */
const camera = new THREE.PerspectiveCamera(75, Size.width / Size.height, 0.1, 100)
camera.position.set(4, 1.8, 4)

/**
 * Galaxy
 */
const parameters = {
    count: 5000,
    size: 0.02,
    radius: 5,
    branches: 3,
    spin: 1,
    randomness: 0.2,
    randomnessPower: 3,
    insideColor: '#ff6030',
    outsideColor: '#1b3984',
}

let geometry;
let material;
let points;

const generatorGalaxy = () => {
    if (points) {
        geometry.dispose()
        material.dispose()
        scene.remove(points)
    }
    geometry = new THREE.BufferGeometry()
    const positions = new Float32Array(parameters.count * 3)
    const colors = new Float32Array(parameters.count * 3)
    for (let i = 0; i < parameters.count; i++) {
        const i3 = i * 3
        const radius = Math.random() * parameters.radius
        const branchesAngle = (i % parameters.branches) / parameters.branches * Math.PI * 2
        const spinAngle = parameters.spin * radius

        const randomX = Math.random() ** parameters.randomnessPower * (Math.random() < 0.5 ? 1 : -1) * parameters.randomness * radius
        const randomY = Math.random() ** parameters.randomnessPower * (Math.random() < 0.5 ? 1 : -1) * parameters.randomness * radius
        const randomZ = Math.random() ** parameters.randomnessPower * (Math.random() < 0.5 ? 1 : -1) * parameters.randomness * radius

        positions[i3] = Math.cos(branchesAngle + spinAngle) * radius + randomX
        positions[i3 + 1] = randomY
        positions[i3 + 2] = Math.sin(branchesAngle + spinAngle) * radius + randomZ


        const colorInside = new THREE.Color(parameters.insideColor)
        const colorOutside = new THREE.Color(parameters.outsideColor)

        const mixedColor = colorInside.clone()
        mixedColor.lerp(colorOutside, radius / parameters.radius)

        colors[i3] = mixedColor.r
        colors[i3 + 1] = mixedColor.g
        colors[i3 + 2] = mixedColor.b
    }

    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
    geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3))

    material = new THREE.PointsMaterial({
        size: parameters.size,
        sizeAttenuation: true, //进大远小
        depthWrite: false,
        blending: THREE.AdditiveBlending, //重叠颜色加深合成
        vertexColors: true, //开启顶点着色
    })

    points = new THREE.Points(geometry, material)

    scene.add(points)
}

generatorGalaxy()





/**
 * Renderer
 */
const canvas = document.querySelector('canvas.webgl')
const renderer = new THREE.WebGLRenderer({
    canvas
})
renderer.setSize(Size.width, Size.height)



/**
 * OrbitControls
 */
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true


/**
 * Update
 */
const clock = new THREE.Clock()
const tick = () => {
    const elapsedTime = clock.getElapsedTime()
    controls.update();
    points.rotation.set(0, elapsedTime * 0.1, 0)
    renderer.render(scene, camera)
    requestAnimationFrame(tick)
}
tick()



/**
 * Debug UI
 */
const gui = new dat.GUI()
gui.add(parameters, 'count', 100, 10000, 100).onFinishChange(generatorGalaxy)
gui.add(parameters, 'size', 0.001, 0.1, 0.001).onFinishChange(generatorGalaxy)
gui.add(parameters, 'radius', 1, 10, 0.01).onFinishChange(generatorGalaxy)
gui.add(parameters, 'branches', 1, 10, 1).onFinishChange(generatorGalaxy)
gui.add(parameters, 'spin', 0, 5, 0.1).onFinishChange(generatorGalaxy)